﻿"""This is an odbc database manipulator"""

from os import path
from mydb.basic import base as superbase
from mydb.basic import table as supertable
from mydb.basic import atable as superatable
import pypyodbc



class base(superbase):
	"This class is an odbc connector"
	#print (self.__doc__)
	#beginning of class suite
	def __init__(self):
		super(base, self).__init__()
		self.driver=pypyodbc
		self.dsn='files'
		self.netdrive='V:'
	
	def open(self):
		"This function opens connection to db"
		#print (self.open.__doc__)
		#beginning of function suite
		self.conn = self.driver.connect(dsn=self.dsn)
		self.cursor = self.conn.cursor()
		return
		
	def execute_in_cycle(self, string, row=None):
		"This function executes statement against base optional for row of values"
		#beginning of function suite
		if not row:
			self.cursor.execute(string)
		else:
			self.cursor.execute(string, [row])
		self.conn.commit()
		#end of function suite
		#Функция ничего не возвращает
		return
	
	def execute_many_in_cycle(self, string, rows):
		"This function executes a statement for rows of values"
		#beginning of function suite
		#Выполняется запрос в зависимости от наличия аргументов
		self.cursor.executemany(string, rows)
		self.conn.commit()
		#end of function suite
		#Функция возвращает результат запроса
		return

	def fetch_in_cycle(self, string, row=None, lim=0):
		"This function fetches a statement optional for row of values"
		#beginning of function suite
		if not row:
			self.cursor.execute(string)
		else:
			self.cursor.execute(string, [row])
		if lim==0:
			result=self.cursor.fetchall()
		else:
			result=self.cursor.fetchmany(lim)
		return result
		#end of function suite
		#Функция возвращает результат запроса

	def commit_in_cycle(self, string):
		"This function executes statement against base and commits it"
		#beginning of function suite
		#end of function suite
		return self.execute_in_cycle(string)

	def execute(self, string, row=None):
		"This function connects to base and executes a statement optional for row of values"
		#beginning of function suite
		#Выполняется подключение к базе данных
		self.connect()
		#Выполняется запрос в зависимости от наличия аргументов
		if not row:
			self.cursor.execute(string)
		else:
			self.cursor.execute(string, [row])
		self.conn.commit()
		#Выполняется отключение от базы данных
		self.disconnect()
		#end of function suite
		#Функция ничего не возвращает
		return

	def execute_many(self, string, rows):
		"This function connects to base and executes a statement for rows of values"
		#beginning of function suite
		#Выполняется подключение к базе данных
		self.connect()
		#Выполняется запрос в зависимости от наличия аргументов
		self.cursor.executemany(string, rows)
		self.conn.commit()
		#Выполняется отключение от базы данных
		self.disconnect()
		#end of function suite
		#Функция возвращает результат запроса
		return
		
	def fetch(self, string, row=None, lim=0):
		"This function connects to base and fetches a statement optional for row of values"
		#beginning of function suite
		#Выполняется подключение к базе данных
		self.connect()
		#Выполняется запрос в зависимости от наличия аргументов
		if not row:
			self.cursor.execute(string)
		else:
			self.cursor.execute(string, [row])
		if lim==0:
			result=self.cursor.fetchall()
		else:
			result=self.cursor.fetchmany(lim)
		self.disconnect()
		return result
		#end of function suite
		#Функция возвращает результат запроса

	def generate(self, string, row=None, lim=1000):
		"This function connects to base and fetches a statement optional for row of values"
		#beginning of function suite
		#Выполняется подключение к базе данных
		self.connect()
		#Выполняется запрос в зависимости от наличия аргументов
		if not row:
			self.cursor.execute(string)
		else:
			self.cursor.execute(string, [row])
		while True:
			results=self.cursor.fetchmany(lim)
			if results==[]: 
				self.disconnect()
				break
			for result in results:
				yield result
		#end of function suite
		#Функция возвращает генератор результатов запроса
	
	def iterate(self, string, row=None, start=None, stop=None, step=None):
		"This function connects to base and executes a statement optional for a row of values"
		#beginning of function suite
		#end of function suite
		#Функция возвращает итератор результатов запроса
		return islice(self.generate(string, row), start, stop, step)

	def commit(self, string):
		"This function connects to base, executes a statement and commits it"
		#beginning of function suite
		#end of function suite
		return self.execute(string)

	#end of class base suite

class relations:
	"This class counts and select records for relations"
	#beginning of class suite
	#print (relations.__doc__)
	#Инициализация:
	def __init__(self):
		self.log=None
		self.base=base()
	
	def SelectTables(self, names=[]):
		'''Function selects tables'''
		#beginning of function suite
		#print(self.SelectTables.__doc__)
		self.base.connect()
		self.base.cursor.tables()
		tables=self.base.cursor.fetchall()
		self.base.disconnect()
		if names==[]:
			result=tables
		else:
			result=[]
			for name in names:
				for table in tables:
					if type(table[2])==bytes:
						table_name=table[2].decode('utf-8')
					else:
						table_name=table[2]
					if type(table[3])==bytes:
						table_type=table[3].decode('utf-8')
					else:
						table_type=table[3]
					if name==table_name and table_type=='TABLE':
						result+=[table]
		#end of function suite
		#Функция возвращает список таблиц в каталоге
		return result

	def SelectlikeTables(self, names=[]):
		'''Function selects tables'''
		#beginning of function suite
		#print(self.SelectTables.__doc__)
		self.base.connect()
		self.base.cursor.tables()
		tables=self.base.cursor.fetchall()
		self.base.disconnect()
		if names==[]:
			result=tables
		else:
			result=[]
			for name in names:
				for table in tables:
					if type(table[2])==bytes:
						table_name=table[2].decode('utf-8')
					else:
						table_name=table[2]
					if type(table[3])==bytes:
						table_type=table[3].decode('utf-8')
					else:
						table_type=table[3]
					if name in table_name and table_type=='TABLE':
						result+=[table]
		#end of function suite
		#Функция возвращает список таблиц в каталоге
		return result

	def SelectAny(self, names=[]):
		'''Function selects tables'''
		#beginning of function suite
		#print(self.SelectTables.__doc__)
		self.base.connect()
		self.base.cursor.tables()
		tables=self.base.cursor.fetchall()
		self.base.disconnect()
		if names==[]:
			result=tables
		else:
			result=[]
			for name in names:
				for table in tables:
					if name==table[2].decode('utf-8'):
						result+=[table]
		#end of function suite
		#Функция возвращает список таблиц в каталоге
		return result

	def SelectlikeAny(self, names=[]):
		'''Function selects tables'''
		#beginning of function suite
		#print(self.SelectTables.__doc__)
		self.base.connect()
		self.base.cursor.tables()
		tables=self.base.cursor.fetchall()
		self.base.disconnect()
		if names==[]:
			result=tables
		else:
			result=[]
			for name in names:
				for table in tables:
					if name in table[2].decode('utf-8'):
						result+=[table]
		#end of function suite
		#Функция возвращает список таблиц в каталоге
		return result

	def CountTables(self, names=[]):
		'''Function counts tables'''
		#beginning of function suite
		#print(self.CountTables.__doc__)
		#end of function suite
		#Функция возвращает число таблиц в каталоге
		return len(self.SelectTables(names))
	
	def CountlikeTables(self, names=[]):
		'''Function counts tables'''
		#beginning of function suite
		#print(self.CountTables.__doc__)
		#end of function suite
		#Функция возвращает число таблиц в каталоге
		return len(self.SelectlikeTables(names))

	def CountAny(self, names=[]):
		'''Function counts tables'''
		#beginning of function suite
		#print(self.CountTables.__doc__)
		#end of function suite
		#Функция возвращает число таблиц в каталоге
		return len(self.SelectAny(names))
	
	def CountlikeAny(self, names=[]):
		'''Function counts tables'''
		#beginning of function suite
		#print(self.CountTables.__doc__)
		#end of function suite
		#Функция возвращает число таблиц в каталоге
		return len(self.SelectlikeAny(names))

	#end of class relations suite

class table(supertable):
	"This class is a manipulater for views"
	#beginning of class suite
	#print (self.__doc__)
	#Инициализация:
	def __init__(self):
		super(table, self).__init__()
		self.seq=False
		self.case=False
		self.base=base()
		self.relations=relations()
		self.relations.base=self.base
	
	def SqlCreateTab(self, param, name, fields, primary, comment):
		"Function returns sql string for the view create query"
		result='CREATE'+' '+param+' '+'TABLE'+' "'+path.join(path.abspath(self.base.netdrive), self.SqlCase(name))+'" '+self.newline
		result+='('+self.newline
		for row in fields:
			result+=self.SqlCase(row[0])+' '+self.SqlCase(row[1])+' '+self.SqlCase(row[2])+','+self.newline
		if primary!='':
			result+='CONSTRAINT'+' '+self.SqlCase(name)+self.constraint_postfix+' '+'PRIMARY KEY ('+self.SqlCase(primary)+')'
		else:
			result=result[:-2]
		result+=self.newline+')'
		result+=self.tab_create_extra(name, comment)
		return result

	def SqlDropTab(self, name):
		"Function returns sql string for the table drop query"
		return 'DROP TABLE'+' "'+self.base.netdrive+''+ self.SqlCase(name))+'" '+self.tab_drop_extra()

	#end of class table suite

class atable(superatable):
	"This class is a manipulator for a table"
	#beginning of class suite
	#print (self.__doc__)
	def __init__(self):
		super(atable, self).__init__()
		self.table=table()

	#end of class atable suite